package com.lhkj.iams.wechat.config.mp;

import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.google.common.collect.Maps;
import com.lhkj.iams.wechat.config.mp.handler.*;
import com.lhkj.iams.wechat.properties.WechatProperties;
import com.lhkj.iams.wechat.properties.WxMpProperties;
import com.lhkj.iams.wechat.properties.WxPayProperties;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.Map;

import static me.chanjar.weixin.common.api.WxConsts.EventType.SUBSCRIBE;
import static me.chanjar.weixin.common.api.WxConsts.EventType.UNSUBSCRIBE;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;


@Configuration
@EnableConfigurationProperties(WechatProperties.class)
public class WxMpConfiguration {

    @Resource
    private WechatProperties wechatProperties;

    /**
     * 默认的公众号id
     */
    public static String DEFAULT_APPID;

    /**
     * 默认的商户号id
     */
    public static String DEFAULT_MCH_ID;

    private final LogHandler logHandler;
    private final NullHandler nullHandler;
    private final KfSessionHandler kfSessionHandler;
    private final StoreCheckNotifyHandler storeCheckNotifyHandler;
    private final LocationHandler locationHandler;
    private final MenuHandler menuHandler;
    private final MsgHandler msgHandler;
    private final ImgHandler imgHandler;
    private final TextMsgHandler textMsgHandler;
    private final UnsubscribeHandler unsubscribeHandler;
    private final SubscribeHandler subscribeHandler;
    private final ScanHandler scanHandler;

    public WxMpConfiguration(LogHandler logHandler, NullHandler nullHandler, KfSessionHandler kfSessionHandler, StoreCheckNotifyHandler storeCheckNotifyHandler, LocationHandler locationHandler, MenuHandler menuHandler, MsgHandler msgHandler, ImgHandler imgHandler, TextMsgHandler textMsgHandler, UnsubscribeHandler unsubscribeHandler, SubscribeHandler subscribeHandler, ScanHandler scanHandler) {
        this.logHandler = logHandler;
        this.nullHandler = nullHandler;
        this.kfSessionHandler = kfSessionHandler;
        this.storeCheckNotifyHandler = storeCheckNotifyHandler;
        this.locationHandler = locationHandler;
        this.menuHandler = menuHandler;
        this.msgHandler = msgHandler;
        this.imgHandler = imgHandler;
        this.textMsgHandler = textMsgHandler;
        this.unsubscribeHandler = unsubscribeHandler;
        this.subscribeHandler = subscribeHandler;
        this.scanHandler = scanHandler;
    }

    /**
     * 单个公众号
     */
    @Bean("wxMpService")
    public WxMpService wxMpService() {
        Map<String, WxMpConfigStorage> configMap = Maps.newHashMap();
        for (WxMpProperties wxMpProperties : wechatProperties.getMps()) {
            WxMpDefaultConfigImpl wxMpDefaultConfig = new WxMpDefaultConfigImpl();
            // 设置微信公众号appId
            wxMpDefaultConfig.setAppId(wxMpProperties.getMpId());
            // 设置微信公众号appSecret
            wxMpDefaultConfig.setSecret(wxMpProperties.getSecret());
            // 设置微信公众号的token
            wxMpDefaultConfig.setToken(wxMpProperties.getToken());
            // 设置微信公众号的EncodingAESKey
            wxMpDefaultConfig.setAesKey(wxMpProperties.getAesKey());
            // 设置公众号授权域名
            wxMpDefaultConfig.setOauth2redirectUri(wxMpProperties.getWechatMpAuthorize());
            if (wxMpProperties.getDefaulted()) {
                DEFAULT_APPID = wxMpProperties.getMpId();
            }
            configMap.put(wxMpDefaultConfig.getAppId(),wxMpDefaultConfig);
        }
        WxMpService service = new WxMpServiceImpl();
        service.setMultiConfigStorages(configMap);
        return service;
    }

    /**
     * 单个公众号
     */
    @Bean("wxPayService")
    public WxPayService wxPayService() {
        Map<String, WxPayConfig> configMap = Maps.newHashMap();
        for (WxPayProperties wxPayProperties : wechatProperties.getPay()) {
            WxPayConfig payConfig = new WxPayConfig();
            payConfig.setAppId(StringUtils.trimToNull(wxPayProperties.getAppId()));
            payConfig.setMchId(StringUtils.trimToNull(wxPayProperties.getMchId()));
            payConfig.setApiV3Key(StringUtils.trimToNull(wxPayProperties.getApiV3Key()));
            payConfig.setNotifyUrl(StringUtils.trimToNull(wxPayProperties.getNotifyUrl()));
            payConfig.setSignType("RSA"); // 默认RSA，目前仅支持RSA
            payConfig.setPrivateKeyPath(StringUtils.trimToNull(wxPayProperties.getKeyPath()));
            payConfig.setPrivateCertPath(StringUtils.trimToNull(wxPayProperties.getCertPath()));
//            payConfig.setSubAppId(StringUtils.trimToNull(wxPayProperties.getSubAppId()));
//            payConfig.setSubMchId(StringUtils.trimToNull(wxPayProperties.getSubMchId()));
//            payConfig.setCertSerialNo(StringUtils.trimToNull(wxPayProperties.getCertSerialNo()));
            // 可以指定是否使用沙箱环境
//            payConfig.setUseSandboxEnv(false);
            if (wxPayProperties.getDefaulted()) {
                DEFAULT_MCH_ID = wxPayProperties.getMchId();
            }
            configMap.put(wxPayProperties.getMchId(),payConfig);
        }
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setMultiConfig(configMap, DEFAULT_MCH_ID);
        return wxPayService;
    }


    @Bean
    public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);

        // 记录所有事件的日志 （异步执行）
        newRouter.rule().handler(this.logHandler).next();

        // 接收客服会话管理事件
        newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION)
                .handler(this.kfSessionHandler).end();
        newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION)
                .handler(this.kfSessionHandler).end();
        newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION)
                .handler(this.kfSessionHandler).end();

        // 门店审核事件
        newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY).handler(this.storeCheckNotifyHandler).end();

        // 自定义菜单事件
        newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.CLICK).handler(this.menuHandler).end();

        // 点击菜单连接事件
        newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.VIEW).handler(this.nullHandler).end();

        // 关注事件
        newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();

        // 取消关注事件
        newRouter.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE).handler(this.unsubscribeHandler).end();

        // 上报地理位置事件
        newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.LOCATION).handler(this.locationHandler).end();

        // 接收地理位置消息
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION).handler(this.locationHandler).end();

        // 扫码事件
        newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.SCAN).handler(this.scanHandler).end();

        // 文本消息处理
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.TEXT).handler(this.textMsgHandler).end();

        // 图片消息处理
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.IMAGE).handler(this.imgHandler).end();

        // 默认
        newRouter.rule().async(false).handler(this.msgHandler).end();

        return newRouter;
    }
}
